// Main32.cpp
// (c) 2011, Charles Lechasseur
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "stdafx.h"
#include "Main.h"

#include "Platform.h"
#include "RegSvr.h"
#include "Exceptions.h"

#include <shellapi.h>


namespace RG64
{
    //
    // 32-bit version of the function to register a 32-bit DLL.
    // We can register as-is.
    //
    // @param p_CmdLine Command-line determining options.
    // @return Program return value.
    //
    int Regsvr64_32bit(const CommandLine& p_CmdLine)
    {
        return PerformRegSvrActions(p_CmdLine);
    }

    //
    // 32-bit version of the function to register a 64-bit DLL.
    // We'll need to call our helper program to do it.
    //
    // @param p_CmdLine Command-line determining options.
    // @return Program return value.
    //
    int Regsvr64_64bit(const CommandLine& p_CmdLine)
    {
        int retValue = 0;

        // Check if we're running on a 64-bit OS.
        // If not, we won't be able to register 64-bit DLLs and we'll skip everything.
        if (Is64BitOS()) {
            // Find the path to the current module.
            // We'll use the 64-bit executable in the same directory.
            char exePath[MAX_PATH + 1];
            DWORD siz = ::GetModuleFileNameA(0, exePath, MAX_PATH + 1);
            if (siz > 0) {
                // Remove the filename and replace it with the name of the 64-bit executable.
                std::string path(exePath);
                std::string::size_type delimPos = path.find_last_of("/\\");
                if (delimPos != std::string::npos) {
                    path.erase(delimPos);
                }
                ATL::CStringA otherExeName(MAKEINTRESOURCEA(IDS_64_BIT_EXE));
                path += "\\";
                path += (LPCSTR) otherExeName;

                // Launch the other executable with the same command-line as this one.
                SHELLEXECUTEINFOA execInfo = { 0 };
                execInfo.cbSize = sizeof(execInfo);
                execInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
                execInfo.hwnd = 0;
                execInfo.lpVerb = 0;
                execInfo.lpFile = path.c_str();
                execInfo.lpParameters = p_CmdLine.OriginalCommandLine().c_str();
                execInfo.lpDirectory = 0;
                execInfo.nShow = SW_SHOWNORMAL;
                if (::ShellExecuteExA(&execInfo) != FALSE && execInfo.hProcess != 0) {
                    // Wait for process to terminate and grab its return value.
                    ::WaitForSingleObject(execInfo.hProcess, INFINITE);
                    DWORD exitCode = 0;
                    if (::GetExitCodeProcess(execInfo.hProcess, &exitCode) != FALSE) {
                        retValue = static_cast<int>(exitCode);
                    }

                    // Don't forget to close the process handle.
                    ::CloseHandle(execInfo.hProcess);
                }
            } else {
                throw Win32Exception();
            }
        } else if (!p_CmdLine.IsSilent()) {
            ATL::CString titleStr(MAKEINTRESOURCE(IDS_APP_TITLE));
            ATL::CString msgStr(MAKEINTRESOURCE(IDS_SKIP_DLL));
            ::MessageBox(0, (LPCTSTR) msgStr, (LPCTSTR) titleStr, MB_OK | MB_ICONINFORMATION);
        }

        return retValue;
    }

} // namespace RG64
